Modelo

source("../../lib/som-utils.R")

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
source("../../lib/maps-utils.R")
Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1

Carga del modelo desde disco

mpr.set_base_path_analysis()
model <- mpr.load_model("som-074.rds.xz")
summary(model)
SOM of size 5x5 with a hexagonal topology and a bubble neighbourhood function.
The number of data layers is 1.
Distance measure(s) used: sumofsquares.
Training data included: 1065343 objects.
Mean distance to the closest unit in the map: 0.396.
plot(model, type="changes")

Carga del dataset de entrada

df <- mpr.load_data("datos_dia_2k.csv.xz")
df
summary(df)
 id_estacion           fecha             fecha_cnt          tmax       
 Length:1065343     Length:1065343     Min.   :  1.0   Min.   :-196.0  
 Class :character   Class :character   1st Qu.: 91.0   1st Qu.: 144.0  
 Mode  :character   Mode  :character   Median :183.0   Median : 201.0  
                                       Mean   :182.8   Mean   : 201.5  
                                       3rd Qu.:274.0   3rd Qu.: 263.0  
                                       Max.   :366.0   Max.   : 469.0  
      tmin             precip            nevada    prof_nieve       
 Min.   :-252.00   Min.   :   0.00   Min.   :0   Min.   :   0.0000  
 1st Qu.:  47.00   1st Qu.:   0.00   1st Qu.:0   1st Qu.:   0.0000  
 Median : 100.00   Median :   0.00   Median :0   Median :   0.0000  
 Mean   :  97.54   Mean   :  17.05   Mean   :0   Mean   :   0.6185  
 3rd Qu.: 153.00   3rd Qu.:   2.00   3rd Qu.:0   3rd Qu.:   0.0000  
 Max.   : 332.00   Max.   :3361.00   Max.   :0   Max.   :1240.0000  
    longitud        latitud           altitud    
 Min.   :27.82   Min.   :-17.889   Min.   :   1  
 1st Qu.:39.47   1st Qu.: -4.850   1st Qu.:  47  
 Median :41.29   Median : -1.411   Median : 287  
 Mean   :40.10   Mean   : -2.391   Mean   : 486  
 3rd Qu.:42.22   3rd Qu.:  1.296   3rd Qu.: 691  
 Max.   :43.57   Max.   :  4.216   Max.   :2535  

Carga de los mapas

world <- ne_countries(scale = "medium", returnclass = "sf")
spain <- subset(world, admin == "Spain")

Mapa de densidad

plot(model, type="count", shape = "straight", palette.name = mpr.degrade.bleu)

NĂºmero de elementos en cada celda:

nb <- table(model$unit.classif)
print(nb)

    1     2     3     4     5     6     7     8     9    10    11    12    13 
14104 53436 15046  3446   583 67919 60764 71114 15741  8352 77013 45946  9049 
   14    15    16    17    18    19    20    21    22    23    24    25 
53446 14691 57040 65178 56484 54459 53413 68515 57010 41249 75810 25535 

ComprobaciĂ³n de nodos vacĂ­os:

dim_model <- 5*5;
len_nb = length(nb);
empty_nodes <- dim_model != len_nb;
if (empty_nodes) {
  print(paste("[Warning] Existen nodos vacĂ­os: ", len_nb, "/", dim_model))
}

Mapa de distancia entre vecinos

plot(model, type="dist.neighbours", shape = "straight")

Influencia de las variables

model_colnames = c("fecha_cnt", "tmax", "tmin", "precip")
model_ncol = length(model_colnames)

Mapa de variables.

plot(model, shape = "straight")

Mapa de calor por variable

par(mfrow=c(3,4))
for (j in 1:model_ncol) {
  plot(model, type="property", property=getCodes(model,1)[,j],
    palette.name=mpr.coolBlueHotRed,
    main=model_colnames[j],
    cex=0.5, shape = "straight")
}

CorrelaciĂ³n para cada columna del vector de nodos

if (!empty_nodes) {
  cor <- apply(getCodes(model,1), 2, mpr.weighted.correlation, w=nb, som=model)
  print(cor)
}
      fecha_cnt       tmax       tmin     precip
[1,] -0.6474238 -0.7312691 -0.7548344  0.2444336
[2,] -0.7562096  0.3257845  0.1979820 -0.1875590

RepresentaciĂ³n de cada variable en un mapa de factores:

if (!empty_nodes) {
  par(mfrow=c(1,1))
  plot(cor[1,], cor[2,], xlim=c(-1,1), ylim=c(-1,1), type="n")
  lines(c(-1,1),c(0,0))
  lines(c(0,0),c(-1,1))
  text(cor[1,], cor[2,], labels=model_colnames, cex=0.75)
  symbols(0,0,circles=1,inches=F,add=T)
}

Importancia de cada variable - varianza ponderada por el tamaño de la celda:

if (!empty_nodes) {
  sigma2 <- sqrt(apply(getCodes(model,1),2,function(x,effectif)
     {m<-sum(effectif*(x-weighted.mean(x,effectif))^2)/(sum(effectif)-1)},
     effectif=nb))
  print(sort(sigma2,decreasing=T))
}
     tmin    precip fecha_cnt      tmax 
0.9498120 0.9497904 0.9496229 0.9411212 

Clustering

if (!empty_nodes) {
  hac <- mpr.hac(model, nb)
}

VisualizaciĂ³n de 3 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=3)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=3)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax             tmin             precip      
 Min.   :  1.0   Min.   :-196.0   Min.   :-252.00   Min.   :  0.00  
 1st Qu.: 92.0   1st Qu.: 146.0   1st Qu.:  47.00   1st Qu.:  0.00  
 Median :183.0   Median : 203.0   Median : 100.00   Median :  0.00  
 Mean   :182.9   Mean   : 202.8   Mean   :  97.95   Mean   : 10.31  
 3rd Qu.:274.0   3rd Qu.: 264.0   3rd Qu.: 154.00   3rd Qu.:  1.00  
 Max.   :366.0   Max.   : 469.0   Max.   : 332.00   Max.   :266.00  
     nevada    prof_nieve           longitud        latitud       
 Min.   :0   Min.   :   0.0000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:39.47   1st Qu.: -4.850  
 Median :0   Median :   0.0000   Median :41.22   Median : -1.411  
 Mean   :0   Mean   :   0.5729   Mean   :40.08   Mean   : -2.403  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.19   3rd Qu.:  1.296  
 Max.   :0   Max.   :1240.0000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  47.0  
 Median : 287.0  
 Mean   : 483.4  
 3rd Qu.: 690.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax             tmin             precip          nevada 
 Min.   :  1.0   Min.   :-124.0   Min.   :-186.00   Min.   :156.0   Min.   :0  
 1st Qu.: 76.0   1st Qu.: 100.0   1st Qu.:  42.00   1st Qu.:235.0   1st Qu.:0  
 Median :148.0   Median : 141.0   Median :  84.00   Median :285.0   Median :0  
 Mean   :174.8   Mean   : 140.1   Mean   :  77.58   Mean   :324.6   Mean   :0  
 3rd Qu.:292.0   3rd Qu.: 184.0   3rd Qu.: 120.00   3rd Qu.:378.0   3rd Qu.:0  
 Max.   :366.0   Max.   : 372.0   Max.   : 254.00   Max.   :822.0   Max.   :0  
   prof_nieve          longitud        latitud            altitud    
 Min.   :   0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.:   0.000   1st Qu.:40.82   1st Qu.: -4.8500   1st Qu.:  69  
 Median :   0.000   Median :42.00   Median :  0.3664   Median : 333  
 Mean   :   2.857   Mean   :41.20   Mean   : -1.8179   Mean   : 614  
 3rd Qu.:   0.000   3rd Qu.:42.53   3rd Qu.:  1.6531   3rd Qu.: 849  
 Max.   :1001.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :  6.0   Min.   :-55.0   Min.   :-92.00   Min.   : 821.0   Min.   :0  
 1st Qu.:112.0   1st Qu.: 95.5   1st Qu.: 54.00   1st Qu.: 891.5   1st Qu.:0  
 Median :273.0   Median :145.0   Median :103.00   Median : 992.0   Median :0  
 Mean   :220.8   Mean   :142.6   Mean   : 92.56   Mean   :1087.7   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:192.5   3rd Qu.:137.50   3rd Qu.:1182.5   3rd Qu.:0  
 Max.   :362.0   Max.   :318.0   Max.   :240.00   Max.   :3361.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.71   1st Qu.:  0.0714   1st Qu.:  44.0  
 Median :  0.000   Median :41.39   Median :  0.8842   Median : 240.0  
 Mean   :  2.209   Mean   :40.54   Mean   : -0.5565   Mean   : 613.4  
 3rd Qu.:  0.000   3rd Qu.:42.24   3rd Qu.:  2.1239   3rd Qu.: 953.0  
 Max.   :559.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

VisualizaciĂ³n de 4 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=4)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=4)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax             tmin          precip            nevada 
 Min.   :  1.0   Min.   :-158.0   Min.   :-240   Min.   :  0.000   Min.   :0  
 1st Qu.:149.0   1st Qu.: 180.0   1st Qu.:  76   1st Qu.:  0.000   1st Qu.:0  
 Median :222.0   Median : 227.0   Median : 122   Median :  0.000   Median :0  
 Mean   :218.6   Mean   : 226.1   Mean   : 118   Mean   :  8.272   Mean   :0  
 3rd Qu.:293.0   3rd Qu.: 279.0   3rd Qu.: 166   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :366.0   Max.   : 469.0   Max.   : 332   Max.   :266.000   Max.   :0  
   prof_nieve           longitud        latitud           altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:38.88   1st Qu.: -5.498   1st Qu.:  42.0  
 Median :   0.0000   Median :41.15   Median : -1.636   Median : 247.0  
 Mean   :   0.1262   Mean   :39.82   Mean   : -2.601   Mean   : 432.1  
 3rd Qu.:   0.0000   3rd Qu.:42.11   3rd Qu.:  1.201   3rd Qu.: 656.0  
 Max.   :1240.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax             tmin             precip          nevada 
 Min.   :  1.0   Min.   :-124.0   Min.   :-186.00   Min.   :156.0   Min.   :0  
 1st Qu.: 76.0   1st Qu.: 100.0   1st Qu.:  42.00   1st Qu.:235.0   1st Qu.:0  
 Median :148.0   Median : 141.0   Median :  84.00   Median :285.0   Median :0  
 Mean   :174.8   Mean   : 140.1   Mean   :  77.58   Mean   :324.6   Mean   :0  
 3rd Qu.:292.0   3rd Qu.: 184.0   3rd Qu.: 120.00   3rd Qu.:378.0   3rd Qu.:0  
 Max.   :366.0   Max.   : 372.0   Max.   : 254.00   Max.   :822.0   Max.   :0  
   prof_nieve          longitud        latitud            altitud    
 Min.   :   0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.:   0.000   1st Qu.:40.82   1st Qu.: -4.8500   1st Qu.:  69  
 Median :   0.000   Median :42.00   Median :  0.3664   Median : 333  
 Mean   :   2.857   Mean   :41.20   Mean   : -1.8179   Mean   : 614  
 3rd Qu.:   0.000   3rd Qu.:42.53   3rd Qu.:  1.6531   3rd Qu.: 849  
 Max.   :1001.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :  6.0   Min.   :-55.0   Min.   :-92.00   Min.   : 821.0   Min.   :0  
 1st Qu.:112.0   1st Qu.: 95.5   1st Qu.: 54.00   1st Qu.: 891.5   1st Qu.:0  
 Median :273.0   Median :145.0   Median :103.00   Median : 992.0   Median :0  
 Mean   :220.8   Mean   :142.6   Mean   : 92.56   Mean   :1087.7   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:192.5   3rd Qu.:137.50   3rd Qu.:1182.5   3rd Qu.:0  
 Max.   :362.0   Max.   :318.0   Max.   :240.00   Max.   :3361.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.71   1st Qu.:  0.0714   1st Qu.:  44.0  
 Median :  0.000   Median :41.39   Median :  0.8842   Median : 240.0  
 Mean   :  2.209   Mean   :40.54   Mean   : -0.5565   Mean   : 613.4  
 3rd Qu.:  0.000   3rd Qu.:42.24   3rd Qu.:  2.1239   3rd Qu.: 953.0  
 Max.   :559.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax             tmin             precip      
 Min.   :  1.0   Min.   :-196.0   Min.   :-252.00   Min.   :  0.00  
 1st Qu.: 23.0   1st Qu.:  92.0   1st Qu.:  -6.00   1st Qu.:  0.00  
 Median : 46.0   Median : 127.0   Median :  27.00   Median :  0.00  
 Mean   : 51.5   Mean   : 117.1   Mean   :  24.16   Mean   : 17.83  
 3rd Qu.: 74.0   3rd Qu.: 152.0   3rd Qu.:  59.00   3rd Qu.: 14.00  
 Max.   :209.0   Max.   : 283.0   Max.   : 175.00   Max.   :235.00  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:40.66   1st Qu.: -4.010  
 Median :0   Median :   0.000   Median :41.63   Median : -1.117  
 Mean   :0   Mean   :   2.218   Mean   :41.04   Mean   : -1.675  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.38   3rd Qu.:  1.384  
 Max.   :0   Max.   :1199.000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.: 108.0  
 Median : 534.0  
 Mean   : 672.2  
 3rd Qu.: 890.0  
 Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

VisualizaciĂ³n de 5 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=5)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=5)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax             tmin             precip      
 Min.   :  6.0   Min.   :-158.0   Min.   :-240.00   Min.   :  0.00  
 1st Qu.:273.0   1st Qu.: 135.0   1st Qu.:  42.00   1st Qu.:  0.00  
 Median :305.0   Median : 187.0   Median :  90.00   Median :  0.00  
 Mean   :301.1   Mean   : 181.1   Mean   :  84.74   Mean   : 15.68  
 3rd Qu.:336.0   3rd Qu.: 235.0   3rd Qu.: 132.00   3rd Qu.:  4.00  
 Max.   :366.0   Max.   : 389.0   Max.   : 264.00   Max.   :266.00  
     nevada    prof_nieve           longitud        latitud       
 Min.   :0   Min.   :   0.0000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:40.07   1st Qu.: -4.767  
 Median :0   Median :   0.0000   Median :41.52   Median : -1.229  
 Mean   :0   Mean   :   0.2796   Mean   :40.49   Mean   : -2.125  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.33   3rd Qu.:  1.366  
 Max.   :0   Max.   :1240.0000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  61.0  
 Median : 370.0  
 Mean   : 548.4  
 3rd Qu.: 788.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax             tmin             precip          nevada 
 Min.   :  1.0   Min.   :-124.0   Min.   :-186.00   Min.   :156.0   Min.   :0  
 1st Qu.: 76.0   1st Qu.: 100.0   1st Qu.:  42.00   1st Qu.:235.0   1st Qu.:0  
 Median :148.0   Median : 141.0   Median :  84.00   Median :285.0   Median :0  
 Mean   :174.8   Mean   : 140.1   Mean   :  77.58   Mean   :324.6   Mean   :0  
 3rd Qu.:292.0   3rd Qu.: 184.0   3rd Qu.: 120.00   3rd Qu.:378.0   3rd Qu.:0  
 Max.   :366.0   Max.   : 372.0   Max.   : 254.00   Max.   :822.0   Max.   :0  
   prof_nieve          longitud        latitud            altitud    
 Min.   :   0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.:   0.000   1st Qu.:40.82   1st Qu.: -4.8500   1st Qu.:  69  
 Median :   0.000   Median :42.00   Median :  0.3664   Median : 333  
 Mean   :   2.857   Mean   :41.20   Mean   : -1.8179   Mean   : 614  
 3rd Qu.:   0.000   3rd Qu.:42.53   3rd Qu.:  1.6531   3rd Qu.: 849  
 Max.   :1001.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :  6.0   Min.   :-55.0   Min.   :-92.00   Min.   : 821.0   Min.   :0  
 1st Qu.:112.0   1st Qu.: 95.5   1st Qu.: 54.00   1st Qu.: 891.5   1st Qu.:0  
 Median :273.0   Median :145.0   Median :103.00   Median : 992.0   Median :0  
 Mean   :220.8   Mean   :142.6   Mean   : 92.56   Mean   :1087.7   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:192.5   3rd Qu.:137.50   3rd Qu.:1182.5   3rd Qu.:0  
 Max.   :362.0   Max.   :318.0   Max.   :240.00   Max.   :3361.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.71   1st Qu.:  0.0714   1st Qu.:  44.0  
 Median :  0.000   Median :41.39   Median :  0.8842   Median : 240.0  
 Mean   :  2.209   Mean   :40.54   Mean   : -0.5565   Mean   : 613.4  
 3rd Qu.:  0.000   3rd Qu.:42.24   3rd Qu.:  2.1239   3rd Qu.: 953.0  
 Max.   :559.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin         precip            nevada 
 Min.   :  1.0   Min.   : 85.0   Min.   :-33   Min.   :  0.000   Min.   :0  
 1st Qu.:116.0   1st Qu.:210.0   1st Qu.:102   1st Qu.:  0.000   1st Qu.:0  
 Median :163.0   Median :259.0   Median :145   Median :  0.000   Median :0  
 Mean   :159.1   Mean   :258.4   Mean   :142   Mean   :  2.929   Mean   :0  
 3rd Qu.:206.0   3rd Qu.:304.0   3rd Qu.:184   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :325.0   Max.   :469.0   Max.   :332   Max.   :128.000   Max.   :0  
   prof_nieve           longitud        latitud           altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:37.96   1st Qu.: -5.616   1st Qu.:  33.0  
 Median :   0.0000   Median :40.84   Median : -1.861   Median : 143.0  
 Mean   :   0.0156   Mean   :39.34   Mean   : -2.944   Mean   : 348.1  
 3rd Qu.:   0.0000   3rd Qu.:41.83   3rd Qu.:  1.099   3rd Qu.: 594.0  
 Max.   :1209.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax             tmin             precip      
 Min.   :  1.0   Min.   :-196.0   Min.   :-252.00   Min.   :  0.00  
 1st Qu.: 23.0   1st Qu.:  92.0   1st Qu.:  -6.00   1st Qu.:  0.00  
 Median : 46.0   Median : 127.0   Median :  27.00   Median :  0.00  
 Mean   : 51.5   Mean   : 117.1   Mean   :  24.16   Mean   : 17.83  
 3rd Qu.: 74.0   3rd Qu.: 152.0   3rd Qu.:  59.00   3rd Qu.: 14.00  
 Max.   :209.0   Max.   : 283.0   Max.   : 175.00   Max.   :235.00  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:40.66   1st Qu.: -4.010  
 Median :0   Median :   0.000   Median :41.63   Median : -1.117  
 Mean   :0   Mean   :   2.218   Mean   :41.04   Mean   : -1.675  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.38   3rd Qu.:  1.384  
 Max.   :0   Max.   :1199.000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.: 108.0  
 Median : 534.0  
 Mean   : 672.2  
 3rd Qu.: 890.0  
 Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

VisualizaciĂ³n de 6 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=6)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=6)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax             tmin             precip      
 Min.   :  6.0   Min.   :-158.0   Min.   :-240.00   Min.   :  0.00  
 1st Qu.:273.0   1st Qu.: 135.0   1st Qu.:  42.00   1st Qu.:  0.00  
 Median :305.0   Median : 187.0   Median :  90.00   Median :  0.00  
 Mean   :301.1   Mean   : 181.1   Mean   :  84.74   Mean   : 15.68  
 3rd Qu.:336.0   3rd Qu.: 235.0   3rd Qu.: 132.00   3rd Qu.:  4.00  
 Max.   :366.0   Max.   : 389.0   Max.   : 264.00   Max.   :266.00  
     nevada    prof_nieve           longitud        latitud       
 Min.   :0   Min.   :   0.0000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:40.07   1st Qu.: -4.767  
 Median :0   Median :   0.0000   Median :41.52   Median : -1.229  
 Mean   :0   Mean   :   0.2796   Mean   :40.49   Mean   : -2.125  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.33   3rd Qu.:  1.366  
 Max.   :0   Max.   :1240.0000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  61.0  
 Median : 370.0  
 Mean   : 548.4  
 3rd Qu.: 788.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin             precip          nevada 
 Min.   :  1.0   Min.   :-84.0   Min.   :-133.00   Min.   :416.0   Min.   :0  
 1st Qu.: 98.0   1st Qu.:103.0   1st Qu.:  50.00   1st Qu.:476.0   1st Qu.:0  
 Median :251.0   Median :144.0   Median :  94.00   Median :535.0   Median :0  
 Mean   :207.5   Mean   :142.8   Mean   :  85.69   Mean   :561.0   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:190.0   3rd Qu.: 130.00   3rd Qu.:629.8   3rd Qu.:0  
 Max.   :366.0   Max.   :369.0   Max.   : 241.00   Max.   :822.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.93   1st Qu.: -3.8314   1st Qu.:  59.0  
 Median :  0.000   Median :41.91   Median :  0.8192   Median : 261.0  
 Mean   :  2.487   Mean   :41.05   Mean   : -1.1715   Mean   : 622.2  
 3rd Qu.:  0.000   3rd Qu.:42.44   3rd Qu.:  1.9356   3rd Qu.: 852.0  
 Max.   :820.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :  6.0   Min.   :-55.0   Min.   :-92.00   Min.   : 821.0   Min.   :0  
 1st Qu.:112.0   1st Qu.: 95.5   1st Qu.: 54.00   1st Qu.: 891.5   1st Qu.:0  
 Median :273.0   Median :145.0   Median :103.00   Median : 992.0   Median :0  
 Mean   :220.8   Mean   :142.6   Mean   : 92.56   Mean   :1087.7   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:192.5   3rd Qu.:137.50   3rd Qu.:1182.5   3rd Qu.:0  
 Max.   :362.0   Max.   :318.0   Max.   :240.00   Max.   :3361.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.71   1st Qu.:  0.0714   1st Qu.:  44.0  
 Median :  0.000   Median :41.39   Median :  0.8842   Median : 240.0  
 Mean   :  2.209   Mean   :40.54   Mean   : -0.5565   Mean   : 613.4  
 3rd Qu.:  0.000   3rd Qu.:42.24   3rd Qu.:  2.1239   3rd Qu.: 953.0  
 Max.   :559.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax             tmin             precip          nevada 
 Min.   :  1.0   Min.   :-124.0   Min.   :-186.00   Min.   :156.0   Min.   :0  
 1st Qu.: 72.0   1st Qu.: 100.0   1st Qu.:  41.00   1st Qu.:227.0   1st Qu.:0  
 Median :135.0   Median : 140.0   Median :  82.00   Median :266.0   Median :0  
 Mean   :168.3   Mean   : 139.6   Mean   :  75.97   Mean   :277.8   Mean   :0  
 3rd Qu.:287.0   3rd Qu.: 183.0   3rd Qu.: 118.00   3rd Qu.:323.0   3rd Qu.:0  
 Max.   :366.0   Max.   : 372.0   Max.   : 254.00   Max.   :449.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :   0.00   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.00   1st Qu.:40.82   1st Qu.: -5.346   1st Qu.:  71.0  
 Median :   0.00   Median :42.07   Median : -0.500   Median : 336.0  
 Mean   :   2.93   Mean   :41.23   Mean   : -1.946   Mean   : 612.4  
 3rd Qu.:   0.00   3rd Qu.:42.59   3rd Qu.:  1.524   3rd Qu.: 849.0  
 Max.   :1001.00   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax            tmin         precip            nevada 
 Min.   :  1.0   Min.   : 85.0   Min.   :-33   Min.   :  0.000   Min.   :0  
 1st Qu.:116.0   1st Qu.:210.0   1st Qu.:102   1st Qu.:  0.000   1st Qu.:0  
 Median :163.0   Median :259.0   Median :145   Median :  0.000   Median :0  
 Mean   :159.1   Mean   :258.4   Mean   :142   Mean   :  2.929   Mean   :0  
 3rd Qu.:206.0   3rd Qu.:304.0   3rd Qu.:184   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :325.0   Max.   :469.0   Max.   :332   Max.   :128.000   Max.   :0  
   prof_nieve           longitud        latitud           altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:37.96   1st Qu.: -5.616   1st Qu.:  33.0  
 Median :   0.0000   Median :40.84   Median : -1.861   Median : 143.0  
 Mean   :   0.0156   Mean   :39.34   Mean   : -2.944   Mean   : 348.1  
 3rd Qu.:   0.0000   3rd Qu.:41.83   3rd Qu.:  1.099   3rd Qu.: 594.0  
 Max.   :1209.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax             tmin             precip      
 Min.   :  1.0   Min.   :-196.0   Min.   :-252.00   Min.   :  0.00  
 1st Qu.: 23.0   1st Qu.:  92.0   1st Qu.:  -6.00   1st Qu.:  0.00  
 Median : 46.0   Median : 127.0   Median :  27.00   Median :  0.00  
 Mean   : 51.5   Mean   : 117.1   Mean   :  24.16   Mean   : 17.83  
 3rd Qu.: 74.0   3rd Qu.: 152.0   3rd Qu.:  59.00   3rd Qu.: 14.00  
 Max.   :209.0   Max.   : 283.0   Max.   : 175.00   Max.   :235.00  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:40.66   1st Qu.: -4.010  
 Median :0   Median :   0.000   Median :41.63   Median : -1.117  
 Mean   :0   Mean   :   2.218   Mean   :41.04   Mean   : -1.675  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.38   3rd Qu.:  1.384  
 Max.   :0   Max.   :1199.000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.: 108.0  
 Median : 534.0  
 Mean   : 672.2  
 3rd Qu.: 890.0  
 Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

VisualizaciĂ³n de 8 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=8)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=8)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :  6.0   Min.   :-67.0   Min.   :-119.0   Min.   :  0.00   Min.   :0  
 1st Qu.:267.0   1st Qu.:166.0   1st Qu.:  72.0   1st Qu.:  0.00   1st Qu.:0  
 Median :294.0   Median :206.0   Median : 106.0   Median :  0.00   Median :0  
 Mean   :292.5   Mean   :204.1   Mean   : 106.7   Mean   : 18.01   Mean   :0  
 3rd Qu.:323.0   3rd Qu.:244.0   3rd Qu.: 142.0   3rd Qu.:  5.00   3rd Qu.:0  
 Max.   :366.0   Max.   :389.0   Max.   : 264.0   Max.   :266.00   Max.   :0  
   prof_nieve           longitud        latitud           altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:39.49   1st Qu.: -5.346   1st Qu.:  44.0  
 Median :   0.0000   Median :41.38   Median : -1.636   Median : 251.0  
 Mean   :   0.0578   Mean   :40.25   Mean   : -2.384   Mean   : 439.4  
 3rd Qu.:   0.0000   3rd Qu.:42.26   3rd Qu.:  1.363   3rd Qu.: 667.0  
 Max.   :1039.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax             tmin              precip       
 Min.   :188.0   Min.   :-158.0   Min.   :-240.000   Min.   :  0.000  
 1st Qu.:324.0   1st Qu.:  66.0   1st Qu.: -22.000   1st Qu.:  0.000  
 Median :340.0   Median :  95.0   Median :   1.000   Median :  0.000  
 Mean   :335.5   Mean   :  88.7   Mean   :  -3.752   Mean   :  6.307  
 3rd Qu.:353.0   3rd Qu.: 118.0   3rd Qu.:  21.000   3rd Qu.:  1.000  
 Max.   :366.0   Max.   : 230.0   Max.   :  70.000   Max.   :220.000  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :28.31   Min.   :-16.499  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:40.95   1st Qu.: -3.678  
 Median :0   Median :   0.000   Median :41.77   Median :  0.595  
 Mean   :0   Mean   :   1.172   Mean   :41.46   Mean   : -1.084  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.40   3rd Qu.:  1.433  
 Max.   :0   Max.   :1240.000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.: 459.0  
 Median : 788.0  
 Mean   : 987.4  
 3rd Qu.:1130.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin             precip          nevada 
 Min.   :  1.0   Min.   :-84.0   Min.   :-133.00   Min.   :416.0   Min.   :0  
 1st Qu.: 98.0   1st Qu.:103.0   1st Qu.:  50.00   1st Qu.:476.0   1st Qu.:0  
 Median :251.0   Median :144.0   Median :  94.00   Median :535.0   Median :0  
 Mean   :207.5   Mean   :142.8   Mean   :  85.69   Mean   :561.0   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:190.0   3rd Qu.: 130.00   3rd Qu.:629.8   3rd Qu.:0  
 Max.   :366.0   Max.   :369.0   Max.   : 241.00   Max.   :822.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.93   1st Qu.: -3.8314   1st Qu.:  59.0  
 Median :  0.000   Median :41.91   Median :  0.8192   Median : 261.0  
 Mean   :  2.487   Mean   :41.05   Mean   : -1.1715   Mean   : 622.2  
 3rd Qu.:  0.000   3rd Qu.:42.44   3rd Qu.:  1.9356   3rd Qu.: 852.0  
 Max.   :820.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :  6.0   Min.   :-55.0   Min.   :-92.00   Min.   : 821.0   Min.   :0  
 1st Qu.:112.0   1st Qu.: 95.5   1st Qu.: 54.00   1st Qu.: 891.5   1st Qu.:0  
 Median :273.0   Median :145.0   Median :103.00   Median : 992.0   Median :0  
 Mean   :220.8   Mean   :142.6   Mean   : 92.56   Mean   :1087.7   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:192.5   3rd Qu.:137.50   3rd Qu.:1182.5   3rd Qu.:0  
 Max.   :362.0   Max.   :318.0   Max.   :240.00   Max.   :3361.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.71   1st Qu.:  0.0714   1st Qu.:  44.0  
 Median :  0.000   Median :41.39   Median :  0.8842   Median : 240.0  
 Mean   :  2.209   Mean   :40.54   Mean   : -0.5565   Mean   : 613.4  
 3rd Qu.:  0.000   3rd Qu.:42.24   3rd Qu.:  2.1239   3rd Qu.: 953.0  
 Max.   :559.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax             tmin             precip          nevada 
 Min.   :  1.0   Min.   :-124.0   Min.   :-186.00   Min.   :156.0   Min.   :0  
 1st Qu.: 72.0   1st Qu.: 100.0   1st Qu.:  41.00   1st Qu.:227.0   1st Qu.:0  
 Median :135.0   Median : 140.0   Median :  82.00   Median :266.0   Median :0  
 Mean   :168.3   Mean   : 139.6   Mean   :  75.97   Mean   :277.8   Mean   :0  
 3rd Qu.:287.0   3rd Qu.: 183.0   3rd Qu.: 118.00   3rd Qu.:323.0   3rd Qu.:0  
 Max.   :366.0   Max.   : 372.0   Max.   : 254.00   Max.   :449.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :   0.00   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.00   1st Qu.:40.82   1st Qu.: -5.346   1st Qu.:  71.0  
 Median :   0.00   Median :42.07   Median : -0.500   Median : 336.0  
 Mean   :   2.93   Mean   :41.23   Mean   : -1.946   Mean   : 612.4  
 3rd Qu.:   0.00   3rd Qu.:42.59   3rd Qu.:  1.524   3rd Qu.: 849.0  
 Max.   :1001.00   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   : 55.0   Min.   :228.0   Min.   : 60.0   Min.   :  0.000   Min.   :0  
 1st Qu.:188.0   1st Qu.:291.0   1st Qu.:160.0   1st Qu.:  0.000   1st Qu.:0  
 Median :211.0   Median :310.0   Median :188.0   Median :  0.000   Median :0  
 Mean   :211.2   Mean   :314.2   Mean   :184.8   Mean   :  1.391   Mean   :0  
 3rd Qu.:235.0   3rd Qu.:335.0   3rd Qu.:210.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :325.0   Max.   :469.0   Max.   :332.0   Max.   :128.000   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :0.0e+00   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:0.0e+00   1st Qu.:37.96   1st Qu.: -4.846   1st Qu.:  34.0  
 Median :0.0e+00   Median :40.66   Median : -1.411   Median : 147.0  
 Mean   :4.9e-05   Mean   :39.25   Mean   : -2.568   Mean   : 310.8  
 3rd Qu.:0.0e+00   3rd Qu.:41.63   3rd Qu.:  1.165   3rd Qu.: 582.0  
 Max.   :1.0e+01   Max.   :43.57   Max.   :  4.216   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt          tmax             tmin             precip      
 Min.   :  1.0   Min.   :-196.0   Min.   :-252.00   Min.   :  0.00  
 1st Qu.: 23.0   1st Qu.:  92.0   1st Qu.:  -6.00   1st Qu.:  0.00  
 Median : 46.0   Median : 127.0   Median :  27.00   Median :  0.00  
 Mean   : 51.5   Mean   : 117.1   Mean   :  24.16   Mean   : 17.83  
 3rd Qu.: 74.0   3rd Qu.: 152.0   3rd Qu.:  59.00   3rd Qu.: 14.00  
 Max.   :209.0   Max.   : 283.0   Max.   : 175.00   Max.   :235.00  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:40.66   1st Qu.: -4.010  
 Median :0   Median :   0.000   Median :41.63   Median : -1.117  
 Mean   :0   Mean   :   2.218   Mean   :41.04   Mean   : -1.675  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.38   3rd Qu.:  1.384  
 Max.   :0   Max.   :1199.000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.: 108.0  
 Median : 534.0  
 Mean   : 672.2  
 3rd Qu.: 890.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   :  1.0   Min.   : 85.0   Min.   :-33.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 91.0   1st Qu.:190.0   1st Qu.: 80.0   1st Qu.:  0.000   1st Qu.:0  
 Median :124.0   Median :216.0   Median :110.0   Median :  0.000   Median :0  
 Mean   :120.6   Mean   :217.3   Mean   :110.3   Mean   :  4.064   Mean   :0  
 3rd Qu.:152.0   3rd Qu.:244.0   3rd Qu.:142.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :225.0   Max.   :349.0   Max.   :239.0   Max.   :101.000   Max.   :0  
   prof_nieve           longitud        latitud           altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:37.98   1st Qu.: -5.733   1st Qu.:  33.0  
 Median :   0.0000   Median :41.06   Median : -2.039   Median : 143.0  
 Mean   :   0.0271   Mean   :39.40   Mean   : -3.222   Mean   : 375.7  
 3rd Qu.:   0.0000   3rd Qu.:42.12   3rd Qu.:  1.099   3rd Qu.: 611.0  
 Max.   :1209.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

VisualizaciĂ³n de 10 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=10)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=10)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)
  df.cluster09 <- subset(df, cluster==9)
  df.cluster10 <- subset(df, cluster==10)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster09 <- select(df.cluster09, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster10 <- select(df.cluster10, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax            tmin            precip          nevada 
 Min.   :  6.0   Min.   :-67.0   Min.   :-119.0   Min.   : 56.0   Min.   :0  
 1st Qu.:224.0   1st Qu.:132.0   1st Qu.:  73.0   1st Qu.: 93.0   1st Qu.:0  
 Median :287.0   Median :183.0   Median : 112.0   Median :121.0   Median :0  
 Mean   :268.7   Mean   :181.8   Mean   : 106.4   Mean   :128.6   Mean   :0  
 3rd Qu.:323.0   3rd Qu.:230.0   3rd Qu.: 144.0   3rd Qu.:160.0   3rd Qu.:0  
 Max.   :366.0   Max.   :389.0   Max.   : 264.0   Max.   :266.0   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.71   1st Qu.: -5.598   1st Qu.:  71.0  
 Median :  0.0000   Median :41.84   Median : -1.885   Median : 336.0  
 Mean   :  0.3386   Mean   :41.20   Mean   : -2.266   Mean   : 512.7  
 3rd Qu.:  0.0000   3rd Qu.:42.59   3rd Qu.:  1.331   3rd Qu.: 735.0  
 Max.   :500.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax             tmin              precip       
 Min.   :188.0   Min.   :-158.0   Min.   :-240.000   Min.   :  0.000  
 1st Qu.:324.0   1st Qu.:  66.0   1st Qu.: -22.000   1st Qu.:  0.000  
 Median :340.0   Median :  95.0   Median :   1.000   Median :  0.000  
 Mean   :335.5   Mean   :  88.7   Mean   :  -3.752   Mean   :  6.307  
 3rd Qu.:353.0   3rd Qu.: 118.0   3rd Qu.:  21.000   3rd Qu.:  1.000  
 Max.   :366.0   Max.   : 230.0   Max.   :  70.000   Max.   :220.000  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :28.31   Min.   :-16.499  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:40.95   1st Qu.: -3.678  
 Median :0   Median :   0.000   Median :41.77   Median :  0.595  
 Mean   :0   Mean   :   1.172   Mean   :41.46   Mean   : -1.084  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.40   3rd Qu.:  1.433  
 Max.   :0   Max.   :1240.000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.: 459.0  
 Median : 788.0  
 Mean   : 987.4  
 3rd Qu.:1130.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin             precip          nevada 
 Min.   :  1.0   Min.   :-84.0   Min.   :-133.00   Min.   :416.0   Min.   :0  
 1st Qu.: 98.0   1st Qu.:103.0   1st Qu.:  50.00   1st Qu.:476.0   1st Qu.:0  
 Median :251.0   Median :144.0   Median :  94.00   Median :535.0   Median :0  
 Mean   :207.5   Mean   :142.8   Mean   :  85.69   Mean   :561.0   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:190.0   3rd Qu.: 130.00   3rd Qu.:629.8   3rd Qu.:0  
 Max.   :366.0   Max.   :369.0   Max.   : 241.00   Max.   :822.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.93   1st Qu.: -3.8314   1st Qu.:  59.0  
 Median :  0.000   Median :41.91   Median :  0.8192   Median : 261.0  
 Mean   :  2.487   Mean   :41.05   Mean   : -1.1715   Mean   : 622.2  
 3rd Qu.:  0.000   3rd Qu.:42.44   3rd Qu.:  1.9356   3rd Qu.: 852.0  
 Max.   :820.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :  6.0   Min.   :-55.0   Min.   :-92.00   Min.   : 821.0   Min.   :0  
 1st Qu.:112.0   1st Qu.: 95.5   1st Qu.: 54.00   1st Qu.: 891.5   1st Qu.:0  
 Median :273.0   Median :145.0   Median :103.00   Median : 992.0   Median :0  
 Mean   :220.8   Mean   :142.6   Mean   : 92.56   Mean   :1087.7   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:192.5   3rd Qu.:137.50   3rd Qu.:1182.5   3rd Qu.:0  
 Max.   :362.0   Max.   :318.0   Max.   :240.00   Max.   :3361.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.71   1st Qu.:  0.0714   1st Qu.:  44.0  
 Median :  0.000   Median :41.39   Median :  0.8842   Median : 240.0  
 Mean   :  2.209   Mean   :40.54   Mean   : -0.5565   Mean   : 613.4  
 3rd Qu.:  0.000   3rd Qu.:42.24   3rd Qu.:  2.1239   3rd Qu.: 953.0  
 Max.   :559.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax            tmin           precip           nevada 
 Min.   :190.0   Min.   : 82.0   Min.   :-43.0   Min.   : 0.000   Min.   :0  
 1st Qu.:269.0   1st Qu.:170.0   1st Qu.: 72.0   1st Qu.: 0.000   1st Qu.:0  
 Median :295.0   Median :209.0   Median :105.0   Median : 0.000   Median :0  
 Mean   :295.4   Mean   :206.8   Mean   :106.8   Mean   : 4.578   Mean   :0  
 3rd Qu.:323.0   3rd Qu.:245.0   3rd Qu.:141.0   3rd Qu.: 0.000   3rd Qu.:0  
 Max.   :366.0   Max.   :347.0   Max.   :233.0   Max.   :87.000   Max.   :0  
   prof_nieve           longitud        latitud           altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:39.48   1st Qu.: -5.346   1st Qu.:  43.0  
 Median :   0.0000   Median :41.31   Median : -1.411   Median : 247.0  
 Mean   :   0.0237   Mean   :40.14   Mean   : -2.398   Mean   : 430.5  
 3rd Qu.:   0.0000   3rd Qu.:42.23   3rd Qu.:  1.363   3rd Qu.: 656.0  
 Max.   :1039.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax             tmin             precip          nevada 
 Min.   :  1.0   Min.   :-124.0   Min.   :-186.00   Min.   :156.0   Min.   :0  
 1st Qu.: 72.0   1st Qu.: 100.0   1st Qu.:  41.00   1st Qu.:227.0   1st Qu.:0  
 Median :135.0   Median : 140.0   Median :  82.00   Median :266.0   Median :0  
 Mean   :168.3   Mean   : 139.6   Mean   :  75.97   Mean   :277.8   Mean   :0  
 3rd Qu.:287.0   3rd Qu.: 183.0   3rd Qu.: 118.00   3rd Qu.:323.0   3rd Qu.:0  
 Max.   :366.0   Max.   : 372.0   Max.   : 254.00   Max.   :449.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :   0.00   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.00   1st Qu.:40.82   1st Qu.: -5.346   1st Qu.:  71.0  
 Median :   0.00   Median :42.07   Median : -0.500   Median : 336.0  
 Mean   :   2.93   Mean   :41.23   Mean   : -1.946   Mean   : 612.4  
 3rd Qu.:   0.00   3rd Qu.:42.59   3rd Qu.:  1.524   3rd Qu.: 849.0  
 Max.   :1001.00   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   : 55.0   Min.   :228.0   Min.   : 60.0   Min.   :  0.000   Min.   :0  
 1st Qu.:188.0   1st Qu.:291.0   1st Qu.:160.0   1st Qu.:  0.000   1st Qu.:0  
 Median :211.0   Median :310.0   Median :188.0   Median :  0.000   Median :0  
 Mean   :211.2   Mean   :314.2   Mean   :184.8   Mean   :  1.391   Mean   :0  
 3rd Qu.:235.0   3rd Qu.:335.0   3rd Qu.:210.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :325.0   Max.   :469.0   Max.   :332.0   Max.   :128.000   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :0.0e+00   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:0.0e+00   1st Qu.:37.96   1st Qu.: -4.846   1st Qu.:  34.0  
 Median :0.0e+00   Median :40.66   Median : -1.411   Median : 147.0  
 Mean   :4.9e-05   Mean   :39.25   Mean   : -2.568   Mean   : 310.8  
 3rd Qu.:0.0e+00   3rd Qu.:41.63   3rd Qu.:  1.165   3rd Qu.: 582.0  
 Max.   :1.0e+01   Max.   :43.57   Max.   :  4.216   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt           tmax            tmin             precip          nevada 
 Min.   :  1.00   Min.   :  0.0   Min.   :-127.00   Min.   :  0.0   Min.   :0  
 1st Qu.: 22.00   1st Qu.:100.0   1st Qu.:   1.00   1st Qu.:  0.0   1st Qu.:0  
 Median : 46.00   Median :130.0   Median :  31.00   Median :  0.0   Median :0  
 Mean   : 51.56   Mean   :125.5   Mean   :  30.91   Mean   : 17.3   Mean   :0  
 3rd Qu.: 74.00   3rd Qu.:154.0   3rd Qu.:  61.00   3rd Qu.: 12.0   3rd Qu.:0  
 Max.   :209.00   Max.   :283.0   Max.   : 175.00   Max.   :192.0   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :   0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.000   1st Qu.:40.48   1st Qu.: -4.127   1st Qu.:  91.0  
 Median :   0.000   Median :41.59   Median : -1.411   Median : 507.0  
 Mean   :   1.105   Mean   :40.97   Mean   : -1.797   Mean   : 586.6  
 3rd Qu.:   0.000   3rd Qu.:42.36   3rd Qu.:  1.384   3rd Qu.: 846.0  
 Max.   :1069.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster09)
   fecha_cnt           tmax              tmin             precip      
 Min.   :  1.00   Min.   :-196.00   Min.   :-252.00   Min.   :  0.00  
 1st Qu.: 23.00   1st Qu.: -21.00   1st Qu.: -91.00   1st Qu.:  0.00  
 Median : 43.00   Median :   3.00   Median : -66.00   Median :  3.00  
 Mean   : 50.64   Mean   :  -2.26   Mean   : -71.53   Mean   : 25.34  
 3rd Qu.: 72.00   3rd Qu.:  22.00   3rd Qu.: -47.00   3rd Qu.: 37.00  
 Max.   :171.00   Max.   : 121.00   Max.   :   3.00   Max.   :235.00  
     nevada    prof_nieve      longitud        latitud             altitud    
 Min.   :0   Min.   :   0   Min.   :28.31   Min.   :-16.49920   Min.   :   4  
 1st Qu.:0   1st Qu.:   0   1st Qu.:42.05   1st Qu.:  0.72920   1st Qu.:1167  
 Median :0   Median :   0   Median :42.47   Median :  0.98440   Median :2230  
 Mean   :0   Mean   :  18   Mean   :41.98   Mean   :  0.05862   Mean   :1886  
 3rd Qu.:0   3rd Qu.:   0   3rd Qu.:42.64   3rd Qu.:  1.52420   3rd Qu.:2400  
 Max.   :0   Max.   :1199   Max.   :43.36   Max.   :  3.16580   Max.   :2535  
if (!empty_nodes) summary(df.cluster10)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   :  1.0   Min.   : 85.0   Min.   :-33.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 91.0   1st Qu.:190.0   1st Qu.: 80.0   1st Qu.:  0.000   1st Qu.:0  
 Median :124.0   Median :216.0   Median :110.0   Median :  0.000   Median :0  
 Mean   :120.6   Mean   :217.3   Mean   :110.3   Mean   :  4.064   Mean   :0  
 3rd Qu.:152.0   3rd Qu.:244.0   3rd Qu.:142.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :225.0   Max.   :349.0   Max.   :239.0   Max.   :101.000   Max.   :0  
   prof_nieve           longitud        latitud           altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:37.98   1st Qu.: -5.733   1st Qu.:  33.0  
 Median :   0.0000   Median :41.06   Median : -2.039   Median : 143.0  
 Mean   :   0.0271   Mean   :39.40   Mean   : -3.222   Mean   : 375.7  
 3rd Qu.:   0.0000   3rd Qu.:42.12   3rd Qu.:  1.099   3rd Qu.: 611.0  
 Max.   :1209.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1], dim(df.cluster09)[1], dim(df.cluster10)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08", "cluster09", "cluster10"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.hist(df.cluster09)

if (!empty_nodes) mpr.hist(df.cluster10)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster09)

if (!empty_nodes) mpr.boxplot(df.cluster10)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
  df.cluster09.grouped <- mpr.group_by_geo(df.cluster09)
  df.cluster10.grouped <- mpr.group_by_geo(df.cluster10)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster09.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster10.grouped)

LS0tCnRpdGxlOiAiQW7DoWxpc2lzIGRlIG1vZGVsb3MgU09NIC0gRnJlY3VlbmNpYSBkYXRvcyBkZSBlbnRyYWRhOiBkaWEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgTW9kZWxvCgoqIElEOiA3NAoqIERlc2NyaXBjacOzbjogCiogRnJlY3VlbmNpYTogZGlhCiogVmFyaWFibGVzOiBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcAoqIERpbWVuc2lvbmVzIGRlbCBtYXBhOiA1LDUKKiBJdGVyYWNpb25lczogMTAwMDAKKiBQYXLDoW1ldHJvcyBhZGljaW9uYWxlczogCgpgYGB7cn0Kc291cmNlKCIuLi8uLi9saWIvc29tLXV0aWxzLlIiKQpzb3VyY2UoIi4uLy4uL2xpYi9tYXBzLXV0aWxzLlIiKQpgYGAKCiMgQ2FyZ2EgZGVsIG1vZGVsbyBkZXNkZSBkaXNjbwoKYGBge3J9Cm1wci5zZXRfYmFzZV9wYXRoX2FuYWx5c2lzKCkKbW9kZWwgPC0gbXByLmxvYWRfbW9kZWwoInNvbS0wNzQucmRzLnh6IikKc3VtbWFyeShtb2RlbCkKYGBgCgpgYGB7cn0KcGxvdChtb2RlbCwgdHlwZT0iY2hhbmdlcyIpCmBgYAoKIyBDYXJnYSBkZWwgZGF0YXNldCBkZSBlbnRyYWRhCgpgYGB7cn0KZGYgPC0gbXByLmxvYWRfZGF0YSgiZGF0b3NfZGlhXzJrLmNzdi54eiIpCmBgYAoKYGBge3J9CmRmCmBgYAoKYGBge3J9CnN1bW1hcnkoZGYpCmBgYAoKIyBDYXJnYSBkZSBsb3MgbWFwYXMKCmBgYHtyfQp3b3JsZCA8LSBuZV9jb3VudHJpZXMoc2NhbGUgPSAibWVkaXVtIiwgcmV0dXJuY2xhc3MgPSAic2YiKQpzcGFpbiA8LSBzdWJzZXQod29ybGQsIGFkbWluID09ICJTcGFpbiIpCmBgYAoKIyBNYXBhIGRlIGRlbnNpZGFkCgpgYGB7cn0KcGxvdChtb2RlbCwgdHlwZT0iY291bnQiLCBzaGFwZSA9ICJzdHJhaWdodCIsIHBhbGV0dGUubmFtZSA9IG1wci5kZWdyYWRlLmJsZXUpCmBgYAoKTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjZWxkYToKCmBgYHtyfQpuYiA8LSB0YWJsZShtb2RlbCR1bml0LmNsYXNzaWYpCnByaW50KG5iKQpgYGAKQ29tcHJvYmFjacOzbiBkZSBub2RvcyB2YWPDrW9zOgoKYGBge3J9CmRpbV9tb2RlbCA8LSA1KjU7Cmxlbl9uYiA9IGxlbmd0aChuYik7CmVtcHR5X25vZGVzIDwtIGRpbV9tb2RlbCAhPSBsZW5fbmI7CmlmIChlbXB0eV9ub2RlcykgewogIHByaW50KHBhc3RlKCJbV2FybmluZ10gRXhpc3RlbiBub2RvcyB2YWPDrW9zOiAiLCBsZW5fbmIsICIvIiwgZGltX21vZGVsKSkKfQpgYGAKCiMgTWFwYSBkZSBkaXN0YW5jaWEgZW50cmUgdmVjaW5vcwoKYGBge3J9CnBsb3QobW9kZWwsIHR5cGU9ImRpc3QubmVpZ2hib3VycyIsIHNoYXBlID0gInN0cmFpZ2h0IikKYGBgCgojIEluZmx1ZW5jaWEgZGUgbGFzIHZhcmlhYmxlcwoKYGBge3J9Cm1vZGVsX2NvbG5hbWVzID0gYygiZmVjaGFfY250IiwgInRtYXgiLCAidG1pbiIsICJwcmVjaXAiKQptb2RlbF9uY29sID0gbGVuZ3RoKG1vZGVsX2NvbG5hbWVzKQpgYGAKCiMjIE1hcGEgZGUgdmFyaWFibGVzLgoKYGBge3J9CnBsb3QobW9kZWwsIHNoYXBlID0gInN0cmFpZ2h0IikKYGBgCgojIyBNYXBhIGRlIGNhbG9yIHBvciB2YXJpYWJsZQoKYGBge3J9CnBhcihtZnJvdz1jKDMsNCkpCmZvciAoaiBpbiAxOm1vZGVsX25jb2wpIHsKICBwbG90KG1vZGVsLCB0eXBlPSJwcm9wZXJ0eSIsIHByb3BlcnR5PWdldENvZGVzKG1vZGVsLDEpWyxqXSwKICAgIHBhbGV0dGUubmFtZT1tcHIuY29vbEJsdWVIb3RSZWQsCiAgICBtYWluPW1vZGVsX2NvbG5hbWVzW2pdLAogICAgY2V4PTAuNSwgc2hhcGUgPSAic3RyYWlnaHQiKQp9CmBgYAoKIyMgQ29ycmVsYWNpw7NuIHBhcmEgY2FkYSBjb2x1bW5hIGRlbCB2ZWN0b3IgZGUgbm9kb3MKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgY29yIDwtIGFwcGx5KGdldENvZGVzKG1vZGVsLDEpLCAyLCBtcHIud2VpZ2h0ZWQuY29ycmVsYXRpb24sIHc9bmIsIHNvbT1tb2RlbCkKICBwcmludChjb3IpCn0KYGBgCgpSZXByZXNlbnRhY2nDs24gZGUgY2FkYSB2YXJpYWJsZSBlbiB1biBtYXBhIGRlIGZhY3RvcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwYXIobWZyb3c9YygxLDEpKQogIHBsb3QoY29yWzEsXSwgY29yWzIsXSwgeGxpbT1jKC0xLDEpLCB5bGltPWMoLTEsMSksIHR5cGU9Im4iKQogIGxpbmVzKGMoLTEsMSksYygwLDApKQogIGxpbmVzKGMoMCwwKSxjKC0xLDEpKQogIHRleHQoY29yWzEsXSwgY29yWzIsXSwgbGFiZWxzPW1vZGVsX2NvbG5hbWVzLCBjZXg9MC43NSkKICBzeW1ib2xzKDAsMCxjaXJjbGVzPTEsaW5jaGVzPUYsYWRkPVQpCn0KYGBgCgpJbXBvcnRhbmNpYSBkZSBjYWRhIHZhcmlhYmxlIC0gdmFyaWFuemEgcG9uZGVyYWRhIHBvciBlbCB0YW1hw7FvIGRlIGxhIGNlbGRhOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBzaWdtYTIgPC0gc3FydChhcHBseShnZXRDb2Rlcyhtb2RlbCwxKSwyLGZ1bmN0aW9uKHgsZWZmZWN0aWYpCiAgICAge208LXN1bShlZmZlY3RpZiooeC13ZWlnaHRlZC5tZWFuKHgsZWZmZWN0aWYpKV4yKS8oc3VtKGVmZmVjdGlmKS0xKX0sCiAgICAgZWZmZWN0aWY9bmIpKQogIHByaW50KHNvcnQoc2lnbWEyLGRlY3JlYXNpbmc9VCkpCn0KYGBgCgojIENsdXN0ZXJpbmcKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgaGFjIDwtIG1wci5oYWMobW9kZWwsIG5iKQp9CmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgMyBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTMpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz0zKQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDQgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz00KQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9NCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgNSBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTUpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz01KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgNiBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTYpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz02KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQogIGRmLmNsdXN0ZXIwNiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTYpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA1LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDYgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNikKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIsICJjbHVzdGVyMDUiLCAiY2x1c3RlcjA2IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDYpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA2KQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDggY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz04KQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9OCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCiAgZGYuY2x1c3RlcjA1IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NSkKICBkZi5jbHVzdGVyMDYgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT02KQogIGRmLmNsdXN0ZXIwNyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTcpCiAgZGYuY2x1c3RlcjA4IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09OCkKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA1IDwtIHNlbGVjdChkZi5jbHVzdGVyMDUsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNiA8LSBzZWxlY3QoZGYuY2x1c3RlcjA2LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDcgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA4IDwtIHNlbGVjdChkZi5jbHVzdGVyMDgsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwOCkKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSwgZGltKGRmLmNsdXN0ZXIwNylbMV0sIGRpbShkZi5jbHVzdGVyMDgpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiwgImNsdXN0ZXIwNSIsICJjbHVzdGVyMDYiLCAiY2x1c3RlcjA3IiwgImNsdXN0ZXIwOCIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwOCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA4KQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKICBkZi5jbHVzdGVyMDcuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNykKICBkZi5jbHVzdGVyMDguZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOC5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDEwIGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9MTApCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz0xMCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCiAgZGYuY2x1c3RlcjA1IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NSkKICBkZi5jbHVzdGVyMDYgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT02KQogIGRmLmNsdXN0ZXIwNyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTcpCiAgZGYuY2x1c3RlcjA4IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09OCkKICBkZi5jbHVzdGVyMDkgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT05KQogIGRmLmNsdXN0ZXIxMCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEwKQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA2IDwtIHNlbGVjdChkZi5jbHVzdGVyMDYsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNyA8LSBzZWxlY3QoZGYuY2x1c3RlcjA3LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDggPC0gc2VsZWN0KGRmLmNsdXN0ZXIwOCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA5IDwtIHNlbGVjdChkZi5jbHVzdGVyMDksIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIxMCA8LSBzZWxlY3QoZGYuY2x1c3RlcjEwLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA5KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIxMCkKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSwgZGltKGRmLmNsdXN0ZXIwNylbMV0sIGRpbShkZi5jbHVzdGVyMDgpWzFdLCBkaW0oZGYuY2x1c3RlcjA5KVsxXSwgZGltKGRmLmNsdXN0ZXIxMClbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiwgImNsdXN0ZXIwNiIsICJjbHVzdGVyMDciLCAiY2x1c3RlcjA4IiwgImNsdXN0ZXIwOSIsICJjbHVzdGVyMTAiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwOSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjEwKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwOSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjEwKQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKICBkZi5jbHVzdGVyMDcuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNykKICBkZi5jbHVzdGVyMDguZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOCkKICBkZi5jbHVzdGVyMDkuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOSkKICBkZi5jbHVzdGVyMTAuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIxMCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIxMC5ncm91cGVkKQpgYGAK